package typedef

import (
	"fmt"
	"time"
	"sync"
)

type GoThreadPool struct {
	cfg *CfgStruct
	threads []*GoThread
	pleaseStop bool
	bPoolRunningLock sync.Mutex
}

func (this *GoThreadPool) Init(pcfg *CfgStruct) {
	this.cfg = pcfg
	this.threads = make([]*GoThread, 0, 8)
	this.pleaseStop = false
	this.cfg.RunningNumLock = new(sync.Mutex)
	this.cfg.RunningNum = 0
}

// call Run()
func (this *GoThreadPool) Start() {
	this.cfg.RunningNumLock.Lock()
	this.cfg.Stat.Empty()
	if this.cfg.RunningNum != 0 {
		fmt.Printf("INFO: There are already %d goroutine running.\n",
			this.cfg.RunningNum)
	} else {
		fmt.Print("INFO: Starting......")
		this.cfg.Stat.StartTime = time.Now()
		this.Run()
		fmt.Print("Done.\n")
	}
	this.cfg.RunningNumLock.Unlock()
}

// make all goroutine stop, and wait them.
func (this *GoThreadPool) Stop() {
	fmt.Print("INFO: Stopping......")
	this.pleaseStop = true
	this.bPoolRunningLock.Lock()
	this.bPoolRunningLock.Unlock()
	fmt.Print("Done.\n")
}

//func (this *GoThreadPool) Restart() {
//	this.Stop()
//	this.Start()
//}

// called by Start()
func (this *GoThreadPool) Run() {
	var (
		i int = 0	// Just i
		runningNum int = 0
	)
	this.bPoolRunningLock.Lock()
	go func() {
		defer func() {
			this.pleaseStop = false
			this.bPoolRunningLock.Unlock()
		} ()

		// Init thread pool.
		for i = 0; i < this.cfg.Number["PROCESS_NUMBER"]; i = i + 1 {
			if len(this.threads) <= i {
				this.threads = append(this.threads, new(GoThread))
			}
			this.threads[i].Init(this.cfg, i)
			this.threads[i].Run()
		}

		// This is a named loop. Name for break
		loop_event:
		for {
			// Adjust thread number.
			this.cfg.RunningNumLock.Lock()
			runningNum = this.cfg.RunningNum
			this.cfg.RunningNumLock.Unlock()
			if runningNum > this.cfg.Number["PROCESS_NUMBER"] {
				// Stop some thread
				for i = runningNum - 1; i >= this.cfg.Number["PROCESS_NUMBER"];
						i = i - 1 {
					this.threads[i].PleaseStop = true
				}
				this.threads = this.threads[:runningNum]
			} else if runningNum < this.cfg.Number["PROCESS_NUMBER"] {
				// Add some thread
				for i = runningNum; i < this.cfg.Number["PROCESS_NUMBER"];
						i = i + 1 {
					if len(this.threads) <= i {
						this.threads = append(this.threads, new(GoThread))
					}
					this.threads[i].Init(this.cfg, i)
					this.threads[i].Run()
				}
			}

			// Do not run loop too quick...
			if this.cfg.Number["STATUS_REFRESH_TIMEOUT"] > 0 {
				time.Sleep(time.Second *
					time.Duration(this.cfg.Number["STATUS_REFRESH_TIMEOUT"]))
			} else {
				time.Sleep(time.Second * 2 )
			}

			if this.cfg.Number["PROCESS_NUMBER"] != this.cfg.RunningNum {
				continue
			}

			if this.pleaseStop == true {
				for i = 0; i < this.cfg.RunningNum; i = i + 1 {
					this.threads[i].PleaseStop = true
				}
				for ; 0 != this.cfg.RunningNum; {
					time.Sleep(time.Second * 1)
				}
				break loop_event
			}
		}
		return
	} ()
	return
}

//func (this *GoThreadPool) ShowStatus() {
//	this.stat.ShowStat()
//}

